﻿using System;
using System.Collections.Generic;
using System.Speech.Recognition;

namespace Haro.Speech
{
    /// <summary>
    /// Represents the entry point for audio commands provided to Haro.
    /// </summary>
    public static class SpeechInput
    {
        #region GrammarNode
        private struct GrammarNode
        {
            public string GrammarFileAddress;
            public Grammar Grammar;

            public GrammarNode(string Address, Grammar g)
            {
                GrammarFileAddress = Address;
                Grammar = g;
            }
        }
        #endregion

        private static SpeechRecognizer m_Recognizer = null;
        private static SortedDictionary<string, GrammarNode> m_Grammars = new SortedDictionary<string, GrammarNode>();

        #region Enabled Accessor & Modifier
        /// <summary>
        /// Gets or sets the bool value which controlls the on/off nature of the speech
        /// recognition engine.
        /// </summary>
        public static bool Enabled
        {
            get { return m_Recognizer.Enabled; }
            set { m_Recognizer.Enabled = value; }
        }
        #endregion

        #region InitializeSpeechInput
        /// <summary>
        /// Initializes all vital components required to recognize speech.
        /// </summary>
        /// <param name="speechRecognizedHandler">The event handler that will invoked when speech is recognized.</param>
        public static void InitializeSpeechInput(EventHandler<SpeechRecognizedEventArgs> speechRecognizedHandler)
        {
            m_Recognizer = new SpeechRecognizer();
            m_Recognizer.SpeechRecognized += speechRecognizedHandler;
        }
        #endregion

        #region LoadGrammar
        /// <summary>
        /// Adds the specified grammar file to the speech recognizer.
        /// </summary>
        /// <param name="Name">String containing the name of the module's name.</param>
        /// <param name="GrammarFileAddress">String containing the address of the grammar file to be added.</param>
        /// <returns>Returns the name of the root rule in the specified grammar file.  If returned value is string.Empty,
        /// that is the result of an exception being caught.</returns>
        public static string LoadGrammar(string ModuleName, string GrammarFileAddress)
        {
            if (m_Grammars.ContainsKey(ModuleName))
            {
                Debug.Output("Error adding grammar for " + ModuleName + "; grammar for this module is already present.");
                return string.Empty;
            }

            try
            {
                Grammar g = new Grammar(GrammarFileAddress);
                g.Name = ModuleName;
                m_Grammars.Add(g.Name, new GrammarNode(GrammarFileAddress, g));
                m_Recognizer.LoadGrammar(m_Grammars[g.Name].Grammar);
                return g.RuleName;
            }
            catch (Exception e)
            {
                Debug.Output("SpeechInput.LoadGrammar: " + e.Message);
                return string.Empty;
            }
        }
        #endregion

        #region UnloadGrammar
        /// <summary>
        /// Removes the specified grammar file from the speech recognizer.
        /// </summary>
        /// <param name="GrammarFileAddress">Address of the grammar file to be removed.</param>
        public static void UnloadGrammar(string ModuleName)
        {
            if (!m_Grammars.ContainsKey(ModuleName))
            {
                Debug.Output("Error unloading grammar for " + ModuleName + "; no grammar for this module present.");
                return;
            }
            try
            {
                m_Recognizer.UnloadGrammar(m_Grammars[ModuleName].Grammar);
                m_Grammars.Remove(ModuleName);
            }
            catch (Exception) { Debug.Output("Error unloading grammar of module: " + ModuleName); }
        }
        #endregion

        #region ReloadGrammar
        /// <summary>
        /// Reloads a grammar already loaded onto the speech recognition engine.
        /// </summary>
        /// <param name="ModuleName">String containing the name associated with the grammar.</param>
        public static void ReloadGrammar(string ModuleName)
        {
            if (m_Grammars.ContainsKey(ModuleName))
            {
                GrammarNode gn = m_Grammars[ModuleName];
                UnloadGrammar(ModuleName);
                LoadGrammar(ModuleName, gn.GrammarFileAddress);
            }
        }
        #endregion

        #region ContainsGrammarForModule
        /// <summary>
        /// Checks to see if a grammar is currently loaded under the specified module's name.  Returns true if
        /// the grammar exists under this name, returns false otherwise.
        /// </summary>
        /// <param name="ModuleName">String containing the name of the module.</param>
        /// <returns>Returns true if the grammar exists under this name, returns false otherwise.</returns>
        public static bool ContainsGrammarForModule(string ModuleName)
        {
            return m_Grammars.ContainsKey(ModuleName);
        }
        #endregion

        #region Cleanup
        /// <summary>
        /// Cleans up all the resources being used by SpeechInput.
        /// </summary>
        public static void Cleanup()
        {
            m_Recognizer.Dispose();
            m_Recognizer = null;
        }
        #endregion
    }
}
